package com.cloudkinto.service.amazon;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.constant.GlobalConstants;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.SHA256Utils;
import com.cloudkinto.common.utils.XmlUtils;
import com.cloudkinto.dao.ExchangeRateDao;
import com.cloudkinto.dao.ShopDao;
import com.cloudkinto.entity.ExchangeRateDo;
import com.cloudkinto.entity.ShopDo;
import com.cloudkinto.service.amazon.vo.AmazonMarketDto;
import com.cloudkinto.service.order.vo.FeedUploadResultBean;
import com.cloudkinto.service.order.vo.amazon.CreateFeedDocumentResult;
import com.cloudkinto.service.shop.ShopService;
import com.cloudkinto.utils.amazon.AmazonUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Author Administrator
 *
 * @Des
 * @Version
 * @Date 2021/8/11
 */
public abstract class AmazonBaseServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {
    @Autowired
    protected ShopDao shopDao;
    @Autowired
    protected ShopService shopService;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    protected RedisTemplate redisTemplate;
    protected String AMZACCESSTOKEN = "AMZACCESSTOKEN:";
    protected String AMZRDTTOKEN = "AMZDRTTOKEN:";
    protected String AMZADACCESSTOKEN = "AMZADACCESSTOKEN:";
    protected String STSSESSIONTOKEN = "STSSESSIONSTOKEN";
    @Autowired
    private ExchangeRateDao exchangeRateDao;
    protected Logger log = LoggerFactory.getLogger(AmazonBaseServiceImpl.class);

    protected String getAccessToken(ShopDo shopDo) throws Exception {
        String accessToken = (String) redisTemplate.opsForValue().get(AMZACCESSTOKEN + shopDo.getId());
        if (accessToken != null) {
            return accessToken;
        }
        String sessionTokenData = getAwsSTSSessionToken(3L);
        String result = AmazonUtil.spGetToken(GlobalConstants.AmzSpClientId, GlobalConstants.AmzSpClientSecret, shopDo.getAmzSpLwa(), sessionTokenData);
        if (result == null) {
            return null;
        }
        accessToken = result;
        if (StringUtils.isNotBlank(accessToken)) {
            redisTemplate.opsForValue().set(AMZACCESSTOKEN + shopDo.getId(), accessToken, 3000, TimeUnit.SECONDS);
            return accessToken;
        }
        return null;
    }


    protected String getRDTAccessToken(ShopDo shopDo, String amazonOrderId, int type) throws Exception {
        String rdtToken = (String) redisTemplate.opsForValue().get(AMZRDTTOKEN + shopDo.getId());
        if (rdtToken != null && StringUtils.isBlank(amazonOrderId)) {
            return rdtToken;
        }
        AmazonMarketDto marketDo = new AmazonMarketDto();
        List element = new ArrayList();
        String path = "";
        element.add("buyerInfo");
        if (type == 0) {
            element.add("shippingAddress");
            if (StringUtils.isEmpty(amazonOrderId))
                path = "/orders/v0/orders";
            else
                path = "/orders/v0/orders/" + amazonOrderId;
        } else {
            path = "/orders/v0/orders/" + amazonOrderId + "/orderItems";
        }
        String sessionTokenData = getAwsSTSSessionToken(marketDo.getId());
        String accessToken = getAccessToken(shopDo.getId());
        rdtToken = AmazonUtil.spGetRdtToken(marketDo.getEndPoint(), "GET", path
                , element, accessToken, sessionTokenData, getRegionName(shopDo.getMarketId()));
        redisTemplate.opsForValue().set(AMZRDTTOKEN + shopDo.getId(), rdtToken, 3000, TimeUnit.SECONDS);
        return rdtToken;
    }

    //
    // protected String getAdAccessToken(ShopDo shopDo) throws Exception {
    //     String accessToken = (String) redisTemplate.opsForValue().get(AMZADACCESSTOKEN + shopDo.getId());
    //     if (accessToken != null) {
    //         return accessToken;
    //     }
    //     JSONObject result = AmazonUtil.spGetToken(GlobalConstants.AmzAdClientId, GlobalConstants.AmzAdClientSecret, shopDo.getAmzAdLwa(), "");
    //
    //     accessToken = result.getString("access_token");
    //     String refresh_token = result.getString("refresh_token");
    //     if (StringUtils.isNotBlank(accessToken)) {
    //         redisTemplate.opsForValue().set(AMZADACCESSTOKEN + shopDo.getId(), accessToken, 3000, TimeUnit.SECONDS);
    //         return accessToken;
    //     } else if (StringUtils.isNotBlank("error_description")) {
    //         //没获取到 去更新授权状态 过期了
    //         Map param = new HashMap();
    //         param.put("shopId", shopDo.getId());
    //         param.put("type", "ad");
    //         log.error("店铺：" + shopDo.getId() + " 获取广告accessToken失败。" + result.getString("error_description"));
    //         if (result.getString("error_description").contains("The request has an invalid grant parameter : refresh_token. User may have revoked or didn't grant the permission")) {
    //             rabbitTemplate.convertAndSend("amazon.updateAuthStatus", JSON.toJSONString(param));
    //         }
    //     }
    //     return null;
    // }

    protected String getRegionName(Long marketId) {
        if (marketId == 1) {
            return "us-east-1";
        } else if (marketId == 2) {
            return "eu-west-1";
        } else if (marketId == 3) {
            return "us-west-2";
        }
        return "";
    }

    //
    // protected String getAdAccessToken1(Long shopId) throws Exception {
    //     ShopDo shopDo = shopDao.selectOne(new LambdaQueryWrapper<ShopDo>().eq(ShopDo::getId, shopId));
    //     if (shopDo == null) {
    //         return "";
    //     }
    //
    //     return getAdAccessToken(shopDo);
    // }
    //
    //
    // protected String getAdAccessToken() throws Exception {
    //     ShopDo shopDo = shopDao.selectById(33);
    //     return getAdAccessToken(shopDo);
    // }

    protected String getAccessToken(Long shopId) throws Exception {
        ShopDo shopDo = shopDao.selectById(shopId);
        return getAccessToken(shopDo);
    }

    protected String getAwsSTSSessionToken(Long marketId) {
        JSONObject jsonObject;
        jsonObject = (JSONObject) redisTemplate.opsForValue().get(STSSESSIONTOKEN);
        if (jsonObject != null) {
            GlobalConstants.accessSecrityKeySP = jsonObject.getString("AccessKeyId");
            GlobalConstants.secretSecrityKeySP = jsonObject.getString("SecretAccessKey");
            return jsonObject.getString("SessionToken");
        }
        Map parametersMap = new HashMap<>();
        parametersMap.put("Action", "AssumeRole");
        parametersMap.put("Version", "2011-06-15");
        parametersMap.put("RoleArn", "arn:aws:iam::975458911230:role/FBA-SP-API");
        parametersMap.put("RoleSessionName", "dingSession");
        String body = null;
        try {
            if (marketId == 1) {
                body = AmazonUtil.awsSTS("https://sts.us-east-1.amazonaws.com/", "us-east-1", parametersMap);
            } else if (marketId == 2) {
                body = AmazonUtil.awsSTS("https://sts.eu-west-1.amazonaws.com/", "eu-west-1", parametersMap);
            } else if (marketId == 3) {
                body = AmazonUtil.awsSTS("https://sts.us-west-2.amazonaws.com/", "us-west-2", parametersMap);
            }
            jsonObject = XmlUtils.xml2Json(body);
            JSONObject resultData = jsonObject.getJSONObject("AssumeRoleResponse").getJSONArray("AssumeRoleResult").getJSONObject(0).getJSONArray("Credentials").getJSONObject(0);
            redisTemplate.opsForValue().set(STSSESSIONTOKEN, resultData, 3000, TimeUnit.SECONDS);
            GlobalConstants.accessSecrityKeySP = resultData.getString("AccessKeyId");
            GlobalConstants.secretSecrityKeySP = resultData.getString("SecretAccessKey");
            String sessionToken = resultData.getString("SessionToken");
            return sessionToken;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 把提交模板申请
     *
     * @param feedDocumentId 模板id
     * @param accessToken    token
     * @param shopDo
     * @return
     */
    protected String createFeed(String feedDocumentId, String marketplaceId, String accessToken, ShopDo shopDo, String feedType) {
        try {
            Map parametersMap = new HashMap<>();
            AmazonMarketDto marketDo = new AmazonMarketDto();

            List<String> marketplaceIds = new ArrayList<>();
            marketplaceIds.add(marketplaceId);
            parametersMap.put("feedType", feedType);
            parametersMap.put("marketplaceIds", marketplaceIds);
            parametersMap.put("inputFeedDocumentId", feedDocumentId);
            System.out.println(SHA256Utils.getSHA256(JSON.toJSONString(parametersMap)));
            log.debug(JSONObject.toJSONString(parametersMap));
            String body = AmazonUtil.spAPidoPOST(marketDo.getEndPoint() + "/feeds/2021-06-30/feeds",
                    accessToken, getAwsSTSSessionToken(shopDo.getMarketId()), parametersMap, JSON.toJSONString(parametersMap));
            log.debug(body);
            return JSONObject.parseObject(body).getString("feedId");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getFeed(String feedId, String accessToken, String sessionToken, ShopDo shopDo) {
        return this.getFeed(feedId, "", accessToken, sessionToken, shopDo);
    }


    /**
     * 根据模板提交文件查询进度
     *
     * @param feedId
     * @return
     */
    public String getFeed(String feedId, String processingStatus, String accessToken, String sessionToken, ShopDo shopDo) {
        AmazonMarketDto marketDo = new AmazonMarketDto();
        if (!(StringUtils.isNotBlank(processingStatus) && "DONE".equals(processingStatus))) {
            try {
                Thread.sleep(130 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Map parametersMap = new HashMap<>();
        System.out.println(SHA256Utils.getSHA256(JSON.toJSONString(parametersMap)));
        log.debug(JSONObject.toJSONString(parametersMap));
        try {
            String result = AmazonUtil.spAPidoGet(GlobalConstants.AmazonSPAPIURL+ "/feeds/2021-06-30/feeds/" + feedId,
                    accessToken, sessionToken, parametersMap, "");
            JSONObject jsonObject = JSON.parseObject(result);
            if (jsonObject.getJSONArray("errors") != null) {

            } else if ("DONE".equals(jsonObject.getString("processingStatus"))) {
                String resultFeedDocumentId = jsonObject.getString("resultFeedDocumentId");
                byte[] data = getDocument("/feeds/2021-06-30/documents/", resultFeedDocumentId, shopDo, GlobalConstants.AmazonSPAPIURL);
                return new String(data);
            } else if ("IN_PROGRESS".equals(jsonObject.getString("processingStatus")) ||
                    "IN_QUEUE".equals(jsonObject.getString("processingStatus"))) {
                try {
                    Thread.sleep(5 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                getFeed(feedId, jsonObject.getString("processingStatus"), accessToken, sessionToken, shopDo);
            } else {

            }
            return "error";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 创建feeds模板
     *
     * @return
     */
    protected String createFeedsDocuments(String accessToken, ShopDo shopDo) {
        try {
            AmazonMarketDto marketDo = new AmazonMarketDto();
            Map parametersMap = new HashMap<>();
            parametersMap.put("contentType", "text/xml; charset=UTF-8");
            System.out.println(SHA256Utils.getSHA256(JSON.toJSONString(parametersMap)));
            log.debug(JSONObject.toJSONString(parametersMap));
            String body = AmazonUtil.spAPidoPOST(marketDo.getEndPoint() + "/feeds/2021-06-30/documents",
                    accessToken, getAwsSTSSessionToken(shopDo.getMarketId()), parametersMap, JSON.toJSONString(parametersMap));
            log.debug(body);
            return body;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 上传文档，状态 done
     *
     * @param marketplaceId 字符串 不是 id
     * @param dataStr
     * @param messageType
     * @return
     */
    public String uploadFeedsUtils(ShopDo shopBean, String marketplaceId, Object dataStr, String feedType, String messageType) {
        CreateFeedDocumentResult createFeedDocumentResult;
        String accessToken = null;
        try {
            accessToken = getAccessToken(shopBean);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String body1 = createFeedsDocuments(accessToken, shopBean);
        JSONObject jsonObject = JSONObject.parseObject(body1);
        if (jsonObject.getJSONArray("errors") != null) {
//            log.error(jsonObject.get("errors").toString());
//            return null;
            if (jsonObject.getJSONArray("errors").getJSONObject(0).getString("code").equals("Unauthorized")) {
                try {
                    accessToken = getAccessToken(shopBean);
                    return null;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        try {
            createFeedDocumentResult =
                    JSON.parseObject(jsonObject.toString(), CreateFeedDocumentResult.class);
            String body = AmazonUtil.uploadFeedsDocumentsFile(dataStr, shopBean.getAmazonSellerId(),
                    createFeedDocumentResult.getUrl(), messageType);
            if (StringUtils.isBlank(createFeedDocumentResult.getFeedDocumentId())) return null;
            String feedId = createFeed(createFeedDocumentResult.getFeedDocumentId(), marketplaceId, accessToken, shopBean, feedType);
            return feedId;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 上传模板文件 feedtype:POST_ORDER_FULFILLMENT_DATA
     *
     * @param shopId
     * @param dataStr
     * @return
     */
    protected String uploadFeeds(Long shopId, Object dataStr) {
        ShopDo shopBean = getShop(shopId);
        String feedId = this.uploadFeedsUtils(shopBean, GlobalConstants.marketplaceId, dataStr, "POST_ORDER_FULFILLMENT_DATA", "OrderFulfillment");
        if (StringUtils.isBlank(feedId)) {
            return null;
        }
        //查询进度情况 获取到二进制
        JSONObject resultJb = null;
        try {
            String feedData = getFeed(feedId, getAccessToken(shopId), getAwsSTSSessionToken(shopBean.getMarketId()), shopBean);
            resultJb = XmlUtils.xml2Json(feedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (resultJb == null) {
            return null;
        }
        FeedUploadResultBean bean = JSON.parseObject(resultJb.getJSONObject("AmazonEnvelope").getJSONArray("Message")
                .getJSONObject(0).getJSONArray("ProcessingReport").getString(0), FeedUploadResultBean.class);
        if ("Complete".equals(bean.getStatusCode())) {
            return bean.getProcessingSummary().get(0).getMessagesSuccessful();
        }

        return null;
    }
    //
    // protected String getFeedDoc(Long shopId, String feedsDocumentId) {
    //     ShopDo shopBean = getShop(shopId);
    //     try {
    //         try {
    //             Thread.sleep(130 * 1000);
    //         } catch (InterruptedException e) {
    //             e.printStackTrace();
    //         }
    //         AmazonMarketDo marketDo = amazonMarketDao.selectById(shopBean.getMarketId());
    //         Map parametersMap = new HashMap<>();
    //         parametersMap.put("contentType", "text/xml; charset=UTF-8");
    //         System.out.println(SHA256Utils.getSHA256(JSON.toJSONString(parametersMap)));
    //         log.debug(JSONObject.toJSONString(parametersMap));
    //         String body = AmazonUtil.spAPidoGet(marketDo.getEndPoint() + "/feeds/2021-06-30/documents/" + feedsDocumentId,
    //                 getAccessToken(shopBean), getAwsSTSSessionToken(shopBean.getMarketId()), parametersMap, JSON.toJSONString(parametersMap));
    //
    //         log.debug(body);
    //         return body;
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return null;
    // }


    protected ShopDo getShop(Long shopId) {
        return shopDao.selectById(shopId);
    }


    protected byte[] getDocument(String path, String feedDocumentId, ShopDo shopDo, String endpoint) {
        Map parametersMap = new HashMap<>();
        String body = null;
        try {
            body = AmazonUtil.spAPidoGet(endpoint + path + feedDocumentId,
                    getAccessToken(shopDo), getAwsSTSSessionToken(shopDo.getMarketId()), parametersMap, "");
            //{
            //  "errors": [
            //    {
            //      "code": "QuotaExceeded",
            //      "message": "You exceeded your quota for the requested resource.",
            //      "details": ""
            //    }
            //  ]
            //}
            CreateFeedDocumentResult createFeedDocumentResult = JSON.parseObject(JSONObject.parseObject(body).toString(), CreateFeedDocumentResult.
                    class);
            return AmazonUtil.download(createFeedDocumentResult.getUrl(), "application/xml,charset=utf-8").getBytes();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void check(String body) {
        if ("".equals(body)) {
            throw new BizException("连接超时");
        } else if (String.valueOf(body.charAt(0)).equals("{")) {
            JSONObject jsonObject = JSONObject.parseObject(body);
            String msg = jsonObject.getString("details") != null ? jsonObject.getString("details") : jsonObject.getString("description");
            throw new BizException(msg);
        }
    }

    public Map<String, Object> checkBody(String body) {
        Map<String, Object> resultMap = new HashMap<>();
        if ("".equals(body)) {
            resultMap.put("code", "FAIL");
            resultMap.put("msg", "连接超时");
            return resultMap;
        } else if (String.valueOf(body.charAt(0)).equals("{")) {
            JSONObject result = JSONObject.parseObject(body);
            resultMap.put("code", "FAIL");
            resultMap.put("msg", StringUtils.isNotBlank(result.getString("details")) ? result.getString("details") : result.getString("description"));
            resultMap.putIfAbsent("msg", "未识别错误");
            return resultMap;
        }
        resultMap.put("code", "SUCCESS");
        return resultMap;
    }

    public void checkThrow(String body) {
        if ("".equals(body)) {
            throw new BizException("连接超时");
        } else if (String.valueOf(body.charAt(0)).equals("{")) {
            JSONObject jsonObject = JSONObject.parseObject(body);
            String msg = jsonObject.getString("details") != null ? jsonObject.getString("details") : jsonObject.getString("description");
//            throw new BizException(msg);
        }
    }

    public boolean checkBoolean(String body) {
        if ("".equals(body)) {
            return false;
        } else return !String.valueOf(body.charAt(0)).equals("{");
    }


    protected ExchangeRateDo getRate(Long type) {
        QueryWrapper exrateWrapper = new QueryWrapper();
        exrateWrapper.orderByDesc("id");
        exrateWrapper.eq("type", type);
        exrateWrapper.last("limit 1");
        ExchangeRateDo exchangeRate = exchangeRateDao.selectOne(exrateWrapper);
        return exchangeRate;
    }

    protected float getRateFromOneToAnother(Long sourceType, Long targetType) {
        if (sourceType == null || targetType == null || sourceType == 0 || targetType == 0) return 0;
        float source = getRate(sourceType).getRate();
        float target = getRate(targetType).getRate();
        float result = source / target;
        return result;
    }
    //
    // public float getRateByCurrency(Long currencyType) {
    //     float rate = 0F;
    //     ExchangeRateDo exchangeRateDo = null;
    //     if (currencyType.equals(DicBusinessItemConstant.CURRENCY_JPY)) {
    //         exchangeRateDo = getRate(0L);
    //     } else if (currencyType.equals(DicBusinessItemConstant.CURRENCY_USD)) {
    //         exchangeRateDo = getRate(1L);
    //     } else if (currencyType.equals(DicBusinessItemConstant.CURRENCY_RMB)) {
    //         rate = 1F;
    //     }
    //     if (exchangeRateDo != null) {
    //         rate = exchangeRateDo.getRate();
    //     }
    //     return rate;
    // }

    protected Double numberFormat(double totalCost) {
        if (Double.isInfinite(totalCost) || Double.isNaN(totalCost))
            return Double.NaN;
        return new BigDecimal(totalCost + "").setScale(2, RoundingMode.UP).doubleValue();
    }

    //
    // protected Long createReports(String reportType, ShopDo shopDo, String endPointUrl, String marketplaceId, Date beginTime, Date endTime) {
    //     String body = null;
    //     List<String> reports = new ArrayList<>();
    //     try {
    //         String bTime = null;
    //         String eTime = null;
    //         if (beginTime != null)
    //             bTime = TimeUtils.formatDate(beginTime, GlobalConstants.TIME_FORMAT_STR, "GMT");
    //         if (endTime != null)
    //             eTime = TimeUtils.formatDate(endTime, GlobalConstants.TIME_FORMAT_STR, "GMT");
    //         body = AmazonUtil.createReports(getAccessToken(shopDo), getAwsSTSSessionToken(shopDo.getMarketId()), reportType, bTime, eTime, marketplaceId, endPointUrl);
    //         JSONObject jsonObject = JSONObject.parseObject(body);
    //         log.debug(jsonObject.toJSONString());
    //         if (jsonObject != null) {
    //             return jsonObject.getLong("reportId");
    //         } else return 0L;
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    //     return 0L;
    // }


}
